home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
parallel
/
communic.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-11
|
15KB
|
476 lines
/*-------------------------------------------------------------------*/
/*----Communications controller between tuple server and client */
/*----processes. Execed by the server, and uses rexec to start */
/*----clients. */
/*---- */
/*----Written by James Pinakis 7/12/89 */
/*----Upgraded by Geoff Sutcliffe 11/4/90 */
/*----Completely re-written by Geoff Sutcliffe 24/8/90 */
/*-------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <netdb.h>
#define BUFFER_SIZE 4096
#define MAX_CLIENT_MACHINES 30
#define MAX_STRING_LENGTH 15
#define ERROR -1
#define SOCKET_EOF -2
#define OK 1
#define COMPLETE 0
#define NULL_DESCRIPTOR -1
/*----Enuerated type for each of the types of messages that may */
/*----appear */
typedef enum
{
machines,
start,
stop,
forward,
exit_communicator,
eof,
blank_line,
error
} request_type;
typedef enum
{
read_ok,
read_eof,
read_blank_line,
read_error
} read_result;
typedef char string_type[MAX_STRING_LENGTH];
typedef char buffer_type[BUFFER_SIZE];
/*----Structure for holding logical and actual machine name, and the */
/*----descriptor for writing and read to/from them */
typedef struct
{
string_type client_machine_name;
string_type machine_name;
int descriptor;
} machine_table_entry_type;
typedef machine_table_entry_type machine_table_type[
MAX_CLIENT_MACHINES];
/*-------------------------------------------------------------------*/
/*----Get the arguments to the communicator. There should be two */
/*----integers - the descriptor for writing to and that for reading */
/*----from. */
void get_argument_values(number_of_arguments,arguments,
write_descriptor,read_descriptor)
int number_of_arguments,*write_descriptor,*read_descriptor;
char *arguments[];
{
int i1;
if (number_of_arguments != 5)
{
(void) fprintf(stderr,"%s: incorrect no. of arguments\n",
arguments[0]);
for (i1=0;i1<number_of_arguments;i1++)
(void) fprintf(stderr,"Argument %d is %s\n",i1,arguments[i1]);
exit(1);
}
*write_descriptor = atoi(arguments[1]);
*read_descriptor = atoi(arguments[2]);
#ifdef DEBUG
(void) fprintf(stderr,"Write_descriptor is %d, Read_descriptor is %d\n",
*write_descriptor,*read_descriptor);
#endif
}
/*-------------------------------------------------------------------*/
/*----Initialise the use of sockets, using tcp protocol */
void initialise_sockets(server_pointer,port_number,read_template)
struct servent **server_pointer;
int *port_number;
fd_set *read_template;
{
*server_pointer = getservbyname("exec","tcp");
if (*server_pointer == NULL)
{
perror("exec - unknown service");
exit(1);
}
*port_number = (*server_pointer)->s_port;
FD_ZERO(read_template);
}
/*-------------------------------------------------------------------*/
/*----Put a logical and absolute machine name into the machine table.*/
/*----A null descriptor is assigned to the machine. */
void load_machine_table(machine_table,entry_number,client_machine_name)
machine_table_type machine_table;
int entry_number;
char *client_machine_name;
{
char *cp1;
#ifdef DEBUG
(void) fprintf(stderr,"Loading machine %s at position %d\n",
client_machine_name,entry_number);
#endif
(void) strcpy(machine_table[entry_number].client_machine_name,
client_machine_name);
cp1 = strchr(client_machine_name,'(');
*cp1 = '\0';
#ifdef DEBUG
(void) fprintf(stderr,"Absolute machine name is %s\n",
client_machine_name);
#endif
(void) strcpy(machine_table[entry_number].machine_name,
client_machine_name);
machine_table[entry_number].descriptor = NULL_DESCRIPTOR;
}
/*-------------------------------------------------------------------*/
/*----Find the index of a given logical machine name in the machine */
/*----table. */
int entry_lookup(machine_table,client_machine_name)
machine_table_type machine_table;
char *client_machine_name;
{
int entry_number;
for (entry_number = 0;entry_number<MAX_CLIENT_MACHINES;entry_number++)
if (!strcmp(client_machine_name,machine_table[entry_number].
client_machine_name))
return(entry_number);
(void) fprintf(stderr,"Machine table does not hold %s\n",
client_machine_name);
return(ERROR);
}
/*-------------------------------------------------------------------*/
/*----Remove unwanted spaces from the buffer */
void tidy_buffer(buffer)
char *buffer;
{
char *new_buffer;
new_buffer = buffer;
while (*buffer != '\0')
{
if (*buffer != ' ')
*new_buffer++ = *buffer;
buffer++;
}
*new_buffer = '\0';
}
/*-------------------------------------------------------------------*/
/*----Read an \n terminated string from a descriptor, into a buffer. */
read_result read_string(buffer,maximum_size,descriptor)
char *buffer;
int maximum_size,descriptor;
{
int this_read,number_read;
#ifdef DEBUG2
fprintf(stderr,"Input on %d\n",descriptor);
#endif
number_read = 0;
while (((this_read = read(descriptor,buffer,1)) > 0) &&
(number_read < maximum_size) && (*buffer != '\n'))
{
#ifdef DEBUG2
(void) fprintf(stderr,".%c",*buffer);
#endif
number_read++;
buffer++;
}
if (this_read == 0)
return(read_eof);
if (this_read < 0)
return(read_error);
if (number_read > maximum_size)
{
#ifdef DEBUG
(void) fprintf(stderr,"Input too long in read_string\n");
#endif
return(read_error);
}
if (number_read == 0)
return(read_blank_line);
/*----Replace \n by \0 */
#ifdef DEBUG
(void) fprintf(stderr,"Length %d\n",number_read);
#endif
*buffer = '\0';
return(read_ok);
}
/*-------------------------------------------------------------------*/
/*----Read input from a descriptor, work out what kind of message it */
/*----is, and fix the arguments so that they are , separated so that */
/*----they can be accessed with strtok. The buffer_pointer is set to */
/*----point to the first argument. */
request_type parse(descriptor,buffer_pointer)
int descriptor;
char **buffer_pointer;
{
request_type request;
static buffer_type buffer;
char *cp1;
switch (read_string(buffer,BUFFER_SIZE,descriptor))
{
case read_error:
return(error);
break;
case read_eof:
return(eof);
break;
case read_blank_line:
return(blank_line);
break;
case read_ok:
tidy_buffer(buffer);
#ifdef DEBUG
(void) fprintf(stderr,"Request =%s=\n",buffer);
#endif
*buffer_pointer = buffer;
/*----Now to get the arguments out by themselves. If there are any */
/*----arguments, then make buffer pointer to them as a string */
if ((cp1 = strrchr(buffer,')')) != NULL)
{
*cp1 = '\0';
if ((cp1 = strchr(buffer,'(')) != NULL)
{
*buffer_pointer = cp1 + 1;
*cp1 = '\0';
}
else return(error);
}
/*----Otherwise put a \0 on the . and buffer pointer is NULL */
else if ((cp1 = strchr(buffer,'.')) != NULL)
{
*cp1 = '\0';
*buffer_pointer = NULL;
}
else return(error);
/*----Decide on the message type */
if (strcmp(buffer,"machines") == 0)
return(machines);
else if (strcmp(buffer,"start") == 0)
return(start);
else if (strcmp(buffer,"stop") == 0)
return(stop);
else if (strcmp(buffer,"forward") == 0)
return(forward);
else if (strcmp(buffer,"exit") == 0)
return(exit_communicator);
else return(error);
break;
default:
return(error);
break;
}
}
/*-------------------------------------------------------------------*/
/*----Start up a client machine using rexec, and update the machine */
/*----table with the descriptor returned. */
void start_machine(machine_table,buffer,port_number,read_template)
machine_table_type machine_table;
char *buffer;
int port_number;
fd_set *read_template;
{
char *client_machine_name,*machine_name;
int descriptor,entry_number;
client_machine_name = strtok(buffer,",");
if ((entry_number = entry_lookup(machine_table,client_machine_name)) !=
ERROR)
{
machine_name = machine_table[entry_number].machine_name;
#ifdef DEBUG
(void) fprintf(stderr,"About to rexec %s\n",machine_name);
#endif
if ((descriptor = rexec(&machine_name,(u_short) port_number,
"geoff","uktt,g","bin/prolog linda/linda",(int *) 0)) == ERROR)
{
perror("Cannot rexec");
return;
}
else {
machine_table[entry_number].descriptor = descriptor;
FD_SET(descriptor,read_template);
#ifdef DEBUG
(void) fprintf(stderr,"%s uses descriptor %d\n",machine_name,
descriptor);
#endif
}
}
}
/*-------------------------------------------------------------------*/
/*----Close the socket for a client machine that has terminated, and */
/*----set the associated descriptor in the machine table to null. */
void stop_machine(machine_table,buffer,read_template)
machine_table_type machine_table;
char *buffer;
fd_set *read_template;
{
int entry_number;
char *client_machine_name;
client_machine_name = strtok(buffer,",");
if ((entry_number = entry_lookup(machine_table,client_machine_name)) !=
ERROR)
{
FD_CLR(machine_table[entry_number].descriptor,read_template);
(void)close(machine_table[entry_number].descriptor);
machine_table[entry_number].descriptor = NULL_DESCRIPTOR;
}
}
/*-------------------------------------------------------------------*/
void forward_message(machine_table,buffer)
machine_table_type machine_table;
char *buffer;
{
char *client_machine_name,*term;
int entry_number;
client_machine_name = buffer;
term = strchr(buffer,',');
*term++ = '\0';
if ((entry_number = entry_lookup(machine_table,client_machine_name)) !=
ERROR)
{
(void) strcat(term,".\n");
#ifdef DEBUG
(void) fprintf(stderr,"Sending =%s= to %s on %d, entry %d\n",term,
client_machine_name,machine_table[entry_number].descriptor,entry_number);
#endif
if (write(machine_table[entry_number].descriptor,term,
strlen(term)) != strlen(term))
perror("Forwarding a term");
}
}
/*-------------------------------------------------------------------*/
int serve_request(machine_table,port_number,read_template)
machine_table_type machine_table;
int port_number;
fd_set *read_template;
{
fd_set detect_template;
int number_of_readable_sockets,entry_number,status;
static int number_of_entries = 2; /*----0 and 1 are the server */
char *buffer,*argument;
detect_template = *read_template;
number_of_readable_sockets = select(FD_SETSIZE,&detect_template,
(fd_set *)0,(fd_set *)0,(struct timeval *)0);
if (number_of_readable_sockets < 0)
{
perror("select");
exit(1);
}
status = OK;
/*----Search for input from entry number 1. 0 is write to server. */
for (entry_number = 0;status == OK && entry_number < number_of_entries;
entry_number++)
if (machine_table[entry_number].descriptor != NULL_DESCRIPTOR &&
FD_ISSET(machine_table[entry_number].descriptor,&detect_template))
{
#ifdef TIME
{
struct timeb time_data;
ftime(&time_data);
printf("=%d %d=\n",time_data.time, time_data.millitm);
}
#endif
#ifdef DEBUG
(void) fprintf(stderr,"Input on %d\n",machine_table[entry_number].
descriptor);
#endif
switch (parse(machine_table[entry_number].descriptor,&buffer))
{
case machines:
argument = strtok(buffer,",");
while (argument != NULL)
{
load_machine_table(machine_table,number_of_entries++,
argument);
argument = strtok((char *)NULL,",");
}
break;
case start:
start_machine(machine_table,buffer,port_number,
read_template);
break;
case stop:
stop_machine(machine_table,buffer,read_template);
break;
case forward:
forward_message(machine_table,buffer);
break;
case exit_communicator:
status = COMPLETE;
break;
case eof:
break;
case blank_line:
break;
case error:
(void) fprintf(stderr,"\nBad input : %s\n",buffer);
status = ERROR;
break;
default:
(void) fprintf(stderr,"Error in serve_request - \
no descriptor found\n");
status = ERROR;
break;
}
}
return(status);
}
/*-------------------------------------------------------------------*/
int main(number_of_arguments,arguments)
int number_of_arguments;
char *arguments[];
{
int read_descriptor,write_descriptor,port_number;
struct servent *server_pointer;
fd_set read_template;
machine_table_type machine_table;
#ifdef DEBUG
int descriptor;
if ((descriptor = open("comm_debug",O_CREAT|O_TRUNC|O_WRONLY,0644)) < 0)
perror("Cannot debug");
else dup2(descriptor,2);
(void) fprintf(stderr,"Communicator is going\n");
#endif
get_argument_values(number_of_arguments,arguments,&write_descriptor,
&read_descriptor);
initialise_sockets(&server_pointer,&port_number,&read_template);
/*----Load write to server details in position 0 of the table */
load_machine_table(machine_table,0,"server(1)");
machine_table[0].descriptor = write_descriptor;
/*----Load read from server details in position 1 */
load_machine_table(machine_table,1,"server(0)");
machine_table[1].descriptor = read_descriptor;
FD_SET(read_descriptor,&read_template);
while (serve_request(machine_table,port_number,&read_template) == OK)
;
#ifdef DEBUG
(void) fprintf(stderr,"Request service completed\n");
#endif
FD_CLR(read_descriptor,&read_template);
#ifdef DEBUG
(void) fprintf(stderr,"Read descriptor cleared\n");
#endif
machine_table[0].descriptor = NULL_DESCRIPTOR;
machine_table[1].descriptor = NULL_DESCRIPTOR;
return(0);
}
/*-------------------------------------------------------------------*/